package com.symaster.gameengine.core;

import java.io.Serial;
import java.io.Serializable;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 组件的顶级父类
 *
 * @author yinmiao
 * @version 2023/11/15
 */
public class Component extends SuperObject implements Serializable {

    @Serial
    private static final long serialVersionUID = 34173241028364213L;

    /**
     * 这个是定义了一个起始值，表示最顶级树形组件的起始值
     */
    public static final int TREE_LAYER_START = 1;

    /**
     * 当前组件的子组件列表
     */
    private final Set<Component> components;

    private final Map<String, List<Component>> componentsByClass;

    /**
     * 当前组件的父级
     */
    private Component parent;
    /**
     * 当前设置的显示层(分组)
     * <p>默认不设置的情况下是0</p>
     *
     * @see #defaultLayer()
     */
    private int layer;
    /**
     * 当前组件在整个组件树下是第几层
     */
    private int treeLayer;

    public Component() {
        this.components = new LinkedHashSet<>();
        this.componentsByClass = new HashMap<>();
        this.layer = defaultLayer();
        this.treeLayer = TREE_LAYER_START;
    }

    private int defaultLayer() {
        return 0;
    }

    /**
     * @return 当前组件层
     * @see #setLayer(int)
     */
    public int getLayer() {
        return layer;
    }

    /**
     * 设置当前组件的层
     *
     * @param layer 层
     */
    public void setLayer(int layer) {
        this.layer = layer;
    }

    /**
     * 获取最顶级组件
     *
     * @return 最顶级组件
     */
    public final Component getTopParent() {
        if (parent == null) {
            return this;
        }
        return parent.getTopParent();
    }

    /**
     * <p>final 修饰，禁止子类重写</p>
     *
     * @return 返回当前组件的所有子组件
     */
    public final Set<Component> getComponents() {
        return components;
    }

    /**
     * 添加子组件
     * <p>final 修饰，禁止子类重写</p>
     *
     * @param component 需要添加的子组件
     */
    public final void addComponent(Component component) {
        if (component != null && component != this) {
            components.add(component);

            String canonicalName = component.getClass().getCanonicalName();

            List<Component> components1 = componentsByClass.computeIfAbsent(canonicalName, k -> new LinkedList<>());
            components1.add(component);

            component.treeLayer = this.treeLayer + 1;
            component.parent = this;
        }
    }

    /**
     * 指定删除子组件
     * <p>final 修饰，禁止子类重写</p>
     *
     * @param component 需要删除的子组件
     */
    public final void removeComponent(Component component) {
        if (component != null && component != this && components.remove(component)) {
            List<Component> components1 = componentsByClass.get(component.getClass().getCanonicalName());
            if (components1 != null) {
                components1.remove(component);
            }

            component.treeLayer = TREE_LAYER_START;
            component.parent = null;
        }
    }

    /**
     * <p>final 修饰，禁止子类重写</p>
     *
     * @return 返回当前组件的父组件，如果没有父组件则返回null
     */
    public final Component getParent() {
        return parent;
    }

    /**
     * 获取当前组件在整个组件树中是第几级
     * <p>final 修饰，禁止子类重写</p>
     *
     * @return 从1开始
     */
    public final int treeLayer() {
        return treeLayer;
    }

    /**
     * 获取组件
     * <p>final 修饰，禁止子类重写</p>
     */
    public final <T extends Component> List<T> getComponents(Class<T> clazz) {
        return getByClass(clazz);
    }

    private <T> List<T> getByClass(Class<T> clazz) {
        String canonicalName = clazz.getCanonicalName();
        List<Component> components1 = componentsByClass.get(canonicalName);
        if (components1 != null && !components1.isEmpty()) {
            return components1.stream().map(clazz::cast).collect(Collectors.toList());
        }

        return Collections.emptyList();
    }

    /**
     * 获取组件
     * <p>final 修饰，禁止子类重写</p>
     *
     * @param deep 是否递归获取, 注意高资源占用操作
     *
     */
    public final <T extends Component> List<T> getComponents(Class<T> clazz, boolean deep) {
        if (!deep) {
            return getComponents(clazz);
        }

        List<T> rtn = new ArrayList<>();

        for (Component component : components) {
            if (clazz.isAssignableFrom(component.getClass())) {
                rtn.add(clazz.cast(component));
            }

            List<T> components1 = component.getComponents(clazz, true);
            if (!components1.isEmpty()) {
                rtn.addAll(components1);
            }
        }

        return rtn;
    }

    /**
     * 获取组件
     * <p>final 修饰，禁止子类重写</p>
     */
    public final <T extends Component> T getComponent(Class<T> clazz) {
        List<Component> components1 = componentsByClass.get(clazz.getCanonicalName());
        if (components1 != null && !components1.isEmpty()) {
            return clazz.cast(components1.get(0));
        }
        return null;
    }

    /**
     * 获取组件
     * <p>final 修饰，禁止子类重写</p>
     */
    public final <T extends SuperInterface> List<T> getComponentByInterface(Class<T> clazz) {
        return getByClass(clazz);
    }

    /**
     * 获取组件
     * <p>final 修饰，禁止子类重写</p>
     *
     * @param deep 是否递归获取, 注意高资源占用操作
     */
    public final <T extends SuperInterface> List<T> getComponentByInterface(Class<T> clazz, boolean deep) {
        if (!deep) {
            return getComponentByInterface(clazz);
        }

        List<T> rtn = new ArrayList<>();

        for (Component component : components) {
            if (clazz.isAssignableFrom(component.getClass())) {
                rtn.add(clazz.cast(component));
            }

            List<T> componentByInterface = component.getComponentByInterface(clazz, true);
            if (!componentByInterface.isEmpty()) {
                rtn.addAll(componentByInterface);
            }
        }

        return rtn;
    }

    /**
     * 获取组件
     * <p>final 修饰，禁止子类重写</p>
     */
    public final List<Component> getComponentsByLayout(int layout) {
        return components.stream()
                .filter(e -> e.getLayer() == layout)
                .collect(Collectors.toList());
    }

    /**
     * 加载当前组件需要的资源
     */
    public void resourceLoad() {
    }
}

